/*
 * This file is part of aion-unique <aion-unique.org>.
 *
 * aion-unique is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aion-unique is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with aion-unique.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.aionemu.gameserver.questEngine.handlers;

import com.aionemu.gameserver.controllers.movement.ActionObserver;
import com.aionemu.gameserver.controllers.movement.ActionObserver.ObserverType;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.model.EmotionType;
import com.aionemu.gameserver.model.TaskId;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Item;
import com.aionemu.gameserver.model.gameobjects.NpcWhichNotGatherable;
import com.aionemu.gameserver.model.gameobjects.VisibleObject;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.templates.npcTemplate.ActionItemTemplate;
import com.aionemu.gameserver.model.templates.quest.QuestItems;
import com.aionemu.gameserver.model.templates.quest.QuestWorkItems;
import com.aionemu.gameserver.network.aion.serverpackets.SM_DIALOG_WINDOW;
import com.aionemu.gameserver.network.aion.serverpackets.SM_EMOTION;
import com.aionemu.gameserver.network.aion.serverpackets.SM_QUEST_ACTION;
import com.aionemu.gameserver.network.aion.serverpackets.SM_USE_OBJECT;
import com.aionemu.gameserver.questEngine.QuestEngine;
import com.aionemu.gameserver.questEngine.model.QuestEnv;
import com.aionemu.gameserver.questEngine.model.QuestState;
import com.aionemu.gameserver.questEngine.model.QuestStatus;
import com.aionemu.gameserver.services.DropService;
import com.aionemu.gameserver.skillengine.model.Skill;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.zone.ZoneName;

/**
 * @author MrPoke
 *
 */
public class QuestHandler
{
	private final Integer	questId;

	protected QuestEngine	qe;

	/**
	 * If quest Aborted or finish this items deleted.
	 */

	protected int[]			deletebleItems;

	public class NpcUseAction
	{
		private final Player		player;
		protected final VisibleObject	target;
		private int					useTime = 3000;
		private ActionObserver		observer;

		/**
		 * @param palyer
		 * @param targetObjectId
		 */
		public NpcUseAction(Player player, VisibleObject target)
		{
			this.player = player;
			this.target = target;
			if (target.getObjectTemplate() instanceof ActionItemTemplate)
				useTime = ((ActionItemTemplate) target.getObjectTemplate()).getTalkDelayTime();
			start();
		}

		public NpcUseAction(Player player, VisibleObject target, int useTime)
		{
			this.player = player;
			this.target = target;
			this.useTime = useTime;
			start();
		}

		protected void start()
		{
			if (player.hasTask(TaskId.ACTION))
				return;
			final ActionObserver observer = new ActionObserver(ObserverType.MOVE, ObserverType.ATTACK, ObserverType.SKILLUSE, ObserverType.ATTACKED)
			{
				@Override
				public void moved()
				{
					abort();
				}

				/* (non-Javadoc)
				 * @see com.aionemu.gameserver.controllers.movement.ActionObserver#attack(com.aionemu.gameserver.model.gameobjects.Creature)
				 */
				@Override
				public void attack(Creature creature)
				{
					abort();
				}

				/* (non-Javadoc)
				 * @see com.aionemu.gameserver.controllers.movement.ActionObserver#skilluse(com.aionemu.gameserver.skillengine.model.Skill)
				 */
				@Override
				public void skilluse(Skill skill)
				{
					abort();
				}

				/* (non-Javadoc)
				 * @see com.aionemu.gameserver.controllers.movement.ActionObserver#attacked(com.aionemu.gameserver.model.gameobjects.Creature)
				 */
				//TODO Need retail....
				@Override
				public void attacked(Creature creature)
				{
					abort();
				}

				private void abort()
				{
					PacketSendUtility.sendPacket(player, new SM_USE_OBJECT(player.getObjectId(), target.getObjectId(), 0, 0));
					player.cancelTask(TaskId.ACTION);
				}
			};

			PacketSendUtility.sendPacket(player, new SM_USE_OBJECT(player.getObjectId(), target.getObjectId(), useTime, 1));
			PacketSendUtility.broadcastPacket(player, new SM_EMOTION(player, EmotionType.START_QUESTLOOT, 0, target.getObjectId()), true);
			player.getObserveController().attach(observer);
			player.addTask(TaskId.ACTION, ThreadPoolManager.getInstance().schedule(new Runnable()
			{
				@Override
				public void run()
				{
					end();
				}
			}, useTime));
		}

		protected void end()
		{
			if (player.getTarget() != target)
				return;
			player.getObserveController().removeObserver(observer);
			PacketSendUtility.broadcastPacket(player, new SM_EMOTION(player, EmotionType.END_QUESTLOOT, 0, target.getObjectId()), true);
			PacketSendUtility.sendPacket(player, new SM_USE_OBJECT(player.getObjectId(), target.getObjectId(), useTime, 0));
		}
		
		protected void loot()
		{
			if (player.getTarget() != target)
				return;
			((NpcWhichNotGatherable)target).onDie(player);
			DropService.getInstance().registerDrop((NpcWhichNotGatherable)target, player, player.getLevel());
			DropService.getInstance().requestDropList(player, (NpcWhichNotGatherable) target);
		}
		
		protected void respawn()
		{
			if (player.getTarget() != target)
				return;
			target.onDespawn();
			((NpcWhichNotGatherable)target).scheduleRespawn();
		}
	}

	protected final void loot(Player player, VisibleObject object)
	{
		new NpcUseAction(player, object)
		{
			@Override
			protected void end()
			{
				super.end();
				loot();
			}
		};
	}
	/**
	 * @param questId
	 */
	protected QuestHandler(Integer questId)
	{
		this.questId = questId;
		this.qe = QuestEngine.getInstance();
	}

	public void deleteQuestItems(QuestEnv env)
	{
		QuestWorkItems qwi = DataManager.QUEST_DATA.getQuestById(env.getQuestId()).getQuestWorkItems();

		Player player = env.getPlayer();
		if (qwi != null)
		{
			for (QuestItems qi : qwi.getQuestWorkItem())
			{
				if (qi != null)
				{
					Item.removeItemFromInventoryByItemId(player, qi.getItemId());
				}
			}
		}
		for (int itemId : deletebleItems)
		{
			Item.removeItemFromInventoryByItemId(player, itemId);
		}
	}

	public synchronized void updateQuestStatus(Player player, QuestState qs)
	{
		PacketSendUtility.sendPacket(player, new SM_QUEST_ACTION(questId, qs.getStatus(), qs.getQuestVars().getQuestVars()));
		if (qs.getStatus() == QuestStatus.COMPLETE)
			player.updateNearbyQuests();
	}

	public boolean sendQuestDialog(QuestEnv env, int dialogId)
	{
		int objectId = 0;
		if (env.getVisibleObject() != null)
			objectId = env.getVisibleObject().getObjectId();
		PacketSendUtility.sendPacket(env.getPlayer(), new SM_DIALOG_WINDOW(objectId, dialogId, questId));
		return true;
	}

	public boolean defaultQuestStartDialog(QuestEnv env)
	{
		switch (env.getDialogId())
		{
			case 1007:
				return sendQuestDialog(env, 4);
			case 1002:
				if (QuestEngine.startQuest(env, QuestStatus.START))
					return sendQuestDialog(env, 1003);
				else
					return false;
			case 1003:
				return sendQuestDialog(env, 1004);
		}
		return false;
	}

	public boolean defaultQuestEndDialog(QuestEnv env)
	{
		Player player = env.getPlayer();
		int targetObjId = env.getVisibleObject() == null ? 0 : env.getVisibleObject().getObjectId();
		switch (env.getDialogId())
		{
			case 8:
			case 9:
			case 10:
			case 11:
			case 12:
			case 13:
			case 14:
			case 15:
			case 16:
			case 17:
				if (QuestEngine.questFinish(env))
				{
					PacketSendUtility.sendPacket(player, new SM_DIALOG_WINDOW(targetObjId, 10));
					return true;
				}
				return false;
			case 1009:
			case -1:
				QuestState qs = player.getQuestStateList().getQuestState(questId);
				if (qs != null && qs.getStatus() == QuestStatus.REWARD)
				{
					return sendQuestDialog(env, 5);
				}
		}
		return false;
	}

	/**
	 * @param env
	 * @param i
	 * @return
	 */
	protected boolean defaultQuestOnLvlUpEvent(QuestEnv env, int i)
	{
		Player player = env.getPlayer();
		QuestState qs = player.getQuestStateList().getQuestState(questId);
		boolean lvlCheck = QuestEngine.checkLevelRequirement(questId, player.getObjectTemplate().getLevel());
		if (qs == null || !lvlCheck || qs.getStatus() != QuestStatus.LOCKED)
			return false;
		if (i != 0)
		{
			QuestState qs2 = player.getQuestStateList().getQuestState(i);
			if (qs2 == null || qs2.getStatus() != QuestStatus.COMPLETE)
				return false;
		}
		qs.setStatus(QuestStatus.START);
		updateQuestStatus(player, qs);
		return true;
	}
	/**
	 * @return the questId
	 */
	public Integer getQuestId()
	{
		return questId;
	}

	public boolean onDialogEvent(QuestEnv questEnv)
	{
		return false;
	}

	public boolean onEnterWorldEvent(QuestEnv questEnv)
	{
		return false;
	}

	public boolean onEnterZoneEvent(QuestEnv questEnv, ZoneName zoneName)
	{
		return false;
	}

	public boolean onItemUseEvent(QuestEnv questEnv, Item item)
	{
		return false;
	}

	public boolean onKillEvent(QuestEnv questEnv)
	{
		return false;
	}

	public boolean onAttackEvent(QuestEnv questEnv)
	{
		return false;
	}

	public boolean onLvlUpEvent(QuestEnv questEnv)
	{
		return false;
	}

	public boolean onDieEvent(QuestEnv questEnv)
	{
		return false;
	}

	public boolean onMovieEndEvent(QuestEnv questEnv, int movieId)
	{
		return false;
	}

	public boolean onQuestAbortEvent(QuestEnv questEnv)
	{
		return false;
	}

	public boolean onQuestTimerEndEvent(QuestEnv questEnv)
	{
		return false;
	}

	public void register()
	{
	}

}
